import axios from 'axios'
import {ElMessage} from "element-plus";
import router from "../router/index.js";

const authItemName = "access_token";

const BASE_URL = "http://localhost:8080";

const defaultFailure = (message, code, url) => {
    console.warn(`请求地址: ${url}, 状态码: ${code}, 错误信息: ${url}`)
    ElMessage.warning(message)
}

const defaultError = (err) => {
    console.error(err)
    ElMessage.error('发生了一些错误，请联系管理员')
}

const defaultSuccess = () => {
    ElMessage.success('后端服务器响应成功')
}

function takeAccessToken() {
    const str = localStorage.getItem(authItemName) || sessionStorage.getItem(authItemName);
    if (!str) return null;
    const authObj = JSON.parse(str);
    if(authObj.expire <= new Date()) {
        deleteAccessTokenAndUsername()
        ElMessage.info('登录状态已过期，请重新登录')
        return null;
    }
    return authObj.token;
}

function unAuthenticated() {
    return !takeAccessToken()
}

function storeAccessToken(token, remember, expire) {
    const authObj = { token: token, expire: expire }
    const str = JSON.stringify(authObj)
    if(remember) localStorage.setItem(authItemName, str)
    else sessionStorage.setItem(authItemName, str)
}

function storeUsername(username, remember) {
    if(remember) localStorage.setItem('username', username)
    else sessionStorage.setItem('username', username)
}

function deleteAccessTokenAndUsername() {
    localStorage.removeItem(authItemName);
    sessionStorage.removeItem(authItemName);
    localStorage.removeItem('username');
    sessionStorage.removeItem('username');
}

async function internalPost(url, data, header, success, failure, error = defaultError) {
    await axios.post(url, data, { headers: header }).then(({data}) => {
        if(data.status === 200) {
            success(data.data)
        } else {
            failure(data.msg, data.status, url)
        }
    }).catch(err => error(err))
}

function internalGet(url, header, success, failure = () => {}, error = defaultError) {
    return axios.get(url, { headers: header })
        .then(response => {
            const data = response.data;
            if (data.status === 200) {
                success(data); // 调用 success 回调并传递数据
                return data; // 返回数据，保持 Promise 链的连续性
            } else {
                failure(data.msg, data.status, url); // 调用 failure 回调
                throw new Error(`Failed with status ${data.status}: ${data.msg}`); // 抛出一个错误，中断 Promise 链并允许 catch 捕获
            }
        })
        .catch(err => {
            error(err); // 调用 error 回调
            throw err; // 重新抛出错误，以便调用者可以处理它（如果需要的话）
        });
}

function login(username, password, remember, success = defaultSuccess, failure = defaultFailure) {
    internalPost(BASE_URL + '/api/auth/login', {
        username: username,
        password: password
    }, {
        'Content-Type': 'application/x-www-form-urlencoded'
    }, (data) => {
        storeAccessToken(data.token, remember, data.expire)
        storeUsername(data.username, remember)
        ElMessage.success('登录成功，欢迎' + data.username)
        success()
    }, failure)
}

function logout(success, failure = defaultFailure) {
    internalPost(BASE_URL + '/api/auth/logout', null, {
        'Authorization': `Bearer ${takeAccessToken()}`,
        'Content-Type': 'application/json'
    }, () => {
        deleteAccessTokenAndUsername()
        ElMessage.success('退出登录成功')
        success()
        }, failure
    )
}

function getDataList(url) {
    return internalGet(BASE_URL + url, {
        'Authorization': `Bearer ${takeAccessToken()}`,
        'Content-Type': 'application/json'
    }, (data) => data)}
    // 成功时直接返回数据，这里其实可以省略 success 回调，直接在 then 中处理
    // 注意：我们省略了 failure 回调的自定义实现，因为它已经在 internalGet 中被处理
    // 如果需要自定义 failure 行为，可以在调用 internalGet 之前或之后处理

async function modifyData(url, successMessage) {
    await internalPost(BASE_URL + url, null, {
        'Authorization': `Bearer ${takeAccessToken()}`,
        'Content-Type': 'application/json',
    }, () =>{
        ElMessage.success(successMessage)
    }, defaultFailure)
}

function turnToTargetPage(targetPage) {
    router.push(targetPage)
}

export {login, logout, unAuthenticated, getDataList, turnToTargetPage, modifyData}